const os = require('os');
const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');

// 获取 CPU 线程数量，最小值为 4
const numCPUs = Math.max(os.cpus().length, 4);

// 封装 HTTP/HTTPS 请求
function fetchUrl(url) {
    return new Promise((resolve, reject) => {
        const protocol = url.startsWith('https') ? https : http;
        protocol.get(url, (response) => {
            if (response.statusCode !== 200) {
                reject(new Error(`Failed to get '${url}' (${response.statusCode})`));
                return;
            }
            resolve(response);
        }).on('error', (err) => {
            reject(err);
        });
    });
}

// 下载文件的函数
async function downloadFile(url, directory) {
    try {
        const response = await fetchUrl(url);

        const totalLength = parseInt(response.headers['content-length'], 10);
        let downloadedLength = 0;

        // 从 URL 中提取文件名
        const urlParts = url.split('/');
        const originalFileName = urlParts[urlParts.length - 1];
        const ext = path.extname(originalFileName);
        const baseName = path.basename(originalFileName, ext);

        // 检查文件是否已经存在
        let fileName = originalFileName;
        let filePath = path.join(directory, fileName);
        let fileIndex = 1;
        let isDuplicate = false;
        while (fs.existsSync(filePath)) {
            if (!isDuplicate) {
                isDuplicate = true;
            }
            // 如果文件名重复，添加索引
            fileName = `${baseName}+${fileIndex}${ext}`;
            filePath = path.join(directory, fileName);
            fileIndex++;
        }

        // 创建写入流并保存文件
        const writer = fs.createWriteStream(filePath);
        response.on('data', (chunk) => {
            downloadedLength += chunk.length;
            const progress = ((downloadedLength / totalLength) * 100).toFixed(2);
            // 打印下载进度
            process.stdout.write(`Downloading ${fileName}: ${progress}%\r`);
        });

        response.pipe(writer);

        return new Promise((resolve, reject) => {
            writer.on('finish', () => {
                console.log(`\nDownloaded ${fileName} successfully.`);
                resolve();
            });

            writer.on('error', (err) => {
                fs.unlink(filePath, () => reject(err)); // 删除部分下载的文件
            });
        });
    } catch (error) {
        console.error(`Error downloading ${url}:`, error);
        throw error; // 抛出错误以便在调用函数中处理
    }
}

// 批量下载函数
async function downloadFiles(urls, directory,path) {
    const failedUrls = [...urls]; // 初始化失败的 URL 列表
    const downloadPromises = [];
    for (let i = 0; i < urls.length; i += numCPUs) {
        const batch = urls.slice(i, i + numCPUs);
        const batchPromises = batch.map(url => 
            downloadFile(url, directory)
                .then(() => {
                    // 成功下载后，从失败列表中移除 URL
                    const index = failedUrls.indexOf(url);
                    if (index > -1) {
                        failedUrls.splice(index, 1);
                    }
                })
                .catch(() => {
                    // 记录下载失败的 URL
                    console.error(`Failed to download: ${url}`);
                })
        );
        downloadPromises.push(...batchPromises);
        await Promise.all(batchPromises);
    }
    await Promise.all(downloadPromises);

    // 将失败的 URL 写回文件
    if (failedUrls.length > 0) {
        fs.writeFileSync(path, failedUrls.join('\n'), 'utf8');
        console.log('Failed URLs have been written back to url.txt');
    } else {
        // 如果没有失败的 URL，清空文件
        fs.writeFileSync(path, '', 'utf8');
        console.log('All files downloaded successfully.');
    }
}

// 从文件中读取 URL
function readUrlsFromFile(filePath) {
    try {
        const data = fs.readFileSync(filePath, 'utf8');
        return data.split('\n').map(line => line.trim()).filter(line => line.length > 0);
    } catch (error) {
        console.error(`Error reading file ${filePath}:`, error);
        return [];
    }
}

// 示例使用
const urlFilePath = './url.txt';
const urls = readUrlsFromFile(urlFilePath);

// 使用文件名生成下载目录
const baseFileName = path.basename(urlFilePath, path.extname(urlFilePath));
const downloadDirectory = path.join('./downloads', baseFileName);

// 检查并创建目录
if (!fs.existsSync(downloadDirectory)) {
    fs.mkdirSync(downloadDirectory, { recursive: true });
}

downloadFiles(urls, downloadDirectory,urlFilePath).then(() => {
    console.log('Download process completed.');
});
